#pragma once
#include <iostream>
#include <unistd.h>
#include <thread>
#include <vector>
#include <queue>
#include "thread.hpp"
#include "LockGuard.hpp"
#include "task.hpp"
#include "log.hpp"
#define dafultName 10

template <class T>
class ThreadPool
{
public:
    bool isEmpty()
    {
        return task_queue.empty();
    }
    T getTask()
    {
        T t = task_queue.front();
        task_queue.pop();

        return t;
    }

    ThreadPool(int num = dafultName)
        : _num(num)
    {
        pthread_mutex_init(&_pmtx, nullptr); // 初始化互斥锁
        pthread_cond_init(&_cond, nullptr);  // 初始化条件变量
        for (int i = 1; i <= _num; i++)
        {
            _threads.push_back(new Thread(i, routine, (void *)this));
        }
    }
    void run()
    {
        for (auto &iter : _threads)
        {
            iter->start(); //?
            // std::cout << iter->getName() << "启动成功" << std::endl;
            logMessage(NORMAL, "%s %s", iter->getName().c_str(), "启动成功");
        }
    }
    // 成员函数有默认的参数：this指针，为了使函数类型与thread.hpp中定义的相同，这里使用static修饰
    // 静态成员函数又只能访问静态变量，若要访问非静态的成员变量呢
    // 在创建线程对象的时候，把整个ThreadPool对象通过this指针传过去，赋值给threadData类中的args变量，
    // 在线程创建好后调用routine函数，threadData会作为参数传递过去，因此在函数内部可以间接访问非静态的成员变量
    static void *routine(void *args) // 获取任务并执行任务
    {
        threadData *tData = (threadData *)args;
        ThreadPool *tp = (ThreadPool *)tData->_args;
        int result;
        while (true)
        {
            task t;
           //花括号中间为自定义临界区，即任务队列是共享的，将任务从共享，拿到自己的私有空间需要加锁
            {
                LockGuard lock(&tp->_pmtx);
                while (tp->isEmpty())
                {
                    pthread_cond_wait(&(tp->_cond), &(tp->_pmtx));
                }
                t = tp->getTask(); // 获取任务
                logMessage(NORMAL, "%s", "获取任务成功");
                // cout<<"获取任务成功"<<endl;
            }
              t(tData->_name);//执行任务
        }
    }
    void push_task(const T &t) // 推送任务到task_queue
    {
        LockGuard lock(&_pmtx);
        task_queue.push(t);
        pthread_cond_signal(&_cond);
    }
    ~ThreadPool()
    {
        for (auto &iter : _threads)
        {
            iter->join();
            delete iter;
        }
        pthread_mutex_destroy(&_pmtx);
        pthread_cond_destroy(&_cond);
    }

private:
    std::vector<Thread *> _threads;
    int _num;
    std::queue<T> task_queue;
    pthread_mutex_t _pmtx;
    pthread_cond_t _cond;
};